package parser;

import java.util.ArrayList;
import java.util.List;
import javax.swing.table.DefaultTableModel;
import net.sf.jsqlparser.expression.AllComparisonExpression;
import net.sf.jsqlparser.expression.AnyComparisonExpression;
import net.sf.jsqlparser.expression.CaseExpression;
import net.sf.jsqlparser.expression.DateValue;
import net.sf.jsqlparser.expression.DoubleValue;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.InverseExpression;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.TimeValue;
import net.sf.jsqlparser.expression.TimestampValue;
import net.sf.jsqlparser.expression.WhenClause;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.SubSelect;

public class OnExpressionParser implements ExpressionVisitor
{
	private DefaultTableModel model1;
	private DefaultTableModel model2;
	private DefaultTableModel resultModel;
	private String joinMode;
	private String columnName;
	public DefaultTableModel GetModel(Expression expression,DefaultTableModel model1,DefaultTableModel model2,String joinMode)
	{
		this.model1 = model1;
		this.model2 = model2;
		this.joinMode = joinMode;
		resultModel = new DefaultTableModel();
		expression.accept(this);
		return resultModel;
	}
	
	public String getColumnName(Expression expression)
	{
		columnName= "";
		expression.accept(this);
		return columnName;
	}
	@Override
	public void visit(NullValue arg0) 
	{
	
	}
	@Override
	public void visit(Function arg0) 
	{
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(InverseExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(JdbcParameter arg0) 
	{
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(DoubleValue arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(LongValue arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(DateValue arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(TimeValue arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(TimestampValue arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Parenthesis arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(StringValue arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Addition arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Division arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Multiplication arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Subtraction arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(AndExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(OrExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Between arg0) {
		// TODO Auto-generated method stub
		
	}
	
	public String getColumnName(String Name)
	{
		int i = Name.indexOf('.');
		return Name.substring(i+1);
	}
	
	public String getTableName(String Name)
	{
		int i = Name.indexOf('.');
		return Name.substring(0,i);
	}
	@Override
	public void visit(EqualsTo equalsTo) 
	{
		OnExpressionParser parser = new OnExpressionParser();
		String columnName1 = parser.getColumnName(equalsTo.getLeftExpression());
		String columnName2 = parser.getColumnName(equalsTo.getRightExpression());
		for (int i=0;i<model1.getColumnCount();i++) resultModel.addColumn(model1.getColumnName(i));
		for (int i=0;i<model2.getColumnCount();i++) resultModel.addColumn(model2.getColumnName(i));
		if (joinMode.equals("Full"))
		{
			List<Integer> insertedRow1 = new ArrayList<Integer>();
			List<Integer> insertedRow2 = new ArrayList<Integer>();
			for (int j=0;j<model1.getRowCount();j++)
			{
				boolean t = true;
				for (int k=0;k<model2.getRowCount();k++) 
					if (model1.getValueAt(j, model1.findColumn(columnName1)).equals(model2.getValueAt(k, model2.findColumn(columnName2))))
						t=false;
				if (t) insertedRow1.add(j);
			}	
			for (int j=0;j<model2.getRowCount();j++)
			{
				boolean t = true;
				for (int k=0;k<model1.getRowCount();k++) 
					if (model1.getValueAt(k, model1.findColumn(columnName1)).equals(model2.getValueAt(j, model2.findColumn(columnName2))))
						t=false;
				if (t) insertedRow2.add(j);
			}	
			for (int j=0;j<model1.getRowCount();j++)
			{
				for (int k=0;k<model2.getRowCount();k++) 
					if (model1.getValueAt(j, model1.findColumn(columnName1)).equals(model2.getValueAt(k, model2.findColumn(columnName2))))
					{
						List<String> values = new ArrayList<String>();
						for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(j, p).toString());
						for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(k, p).toString());
						resultModel.addRow(values.toArray()); 
					}
			}
			for (int i=0;i<insertedRow1.size();i++) 
			{
				List<String> values = new ArrayList<String>();
				for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(insertedRow1.get(i), p).toString());
				for (int p=0;p<model2.getColumnCount();p++) values.add(null);
				resultModel.addRow(values.toArray()); 
			}
			for (int i=0;i<insertedRow2.size();i++) 
			{
				List<String> values = new ArrayList<String>();
				for (int p=0;p<model1.getColumnCount();p++) values.add(null);
				for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(insertedRow2.get(i), p).toString());
				resultModel.addRow(values.toArray()); 
			}
		}
		else if (joinMode.equals("Inner") || joinMode.equals("Simple"))
		{
			for (int j=0;j<model1.getRowCount();j++)
			{
				for (int k=0;k<model2.getRowCount();k++) 
					if (model1.getValueAt(j, model1.findColumn(columnName1)).equals(model2.getValueAt(k, model2.findColumn(columnName2))))
					{
						List<String> values = new ArrayList<String>();
						for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(j, p).toString());
						for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(k, p).toString());
						resultModel.addRow(values.toArray()); 
					}
			}
		}
		else if (joinMode.equals("Left"))
		{
			List<Integer> insertedRow = new ArrayList<Integer>();
			for (int j=0;j<model1.getRowCount();j++)
			{
				boolean t = true;
				for (int k=0;k<model2.getRowCount();k++) 
					if (model1.getValueAt(j, model1.findColumn(columnName1)).equals(model2.getValueAt(k, model2.findColumn(columnName2))))
					{
						List<String> values = new ArrayList<String>();
						for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(j, p).toString());
						for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(k, p).toString());
						resultModel.addRow(values.toArray()); 
						t=false;
					}
				if (t) insertedRow.add(j);
			}	
			for (int i=0;i<insertedRow.size();i++) 
			{
				List<String> values = new ArrayList<String>();
				for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(insertedRow.get(i), p).toString());
				for (int p=0;p<model2.getColumnCount();p++) values.add(null);
				resultModel.addRow(values.toArray()); 
			}
		}
		else if (joinMode.equals("Natural"))
		{
			
		}
		else if (joinMode.equals("Outer"))
		{
			List<Integer> insertedRow1 = new ArrayList<Integer>();
			List<Integer> insertedRow2 = new ArrayList<Integer>();
			for (int j=0;j<model1.getRowCount();j++)
			{
				boolean t = true;
				for (int k=0;k<model2.getRowCount();k++) 
					if (model1.getValueAt(j, model1.findColumn(columnName1)).equals(model2.getValueAt(k, model2.findColumn(columnName2))))
						t=false;
				if (t) insertedRow1.add(j);
			}	
			for (int j=0;j<model2.getRowCount();j++)
			{
				boolean t = true;
				for (int k=0;k<model1.getRowCount();k++) 
					if (model1.getValueAt(k, model1.findColumn(columnName1)).equals(model2.getValueAt(j, model2.findColumn(columnName2))))
						t=false;
				if (t) insertedRow2.add(j);
			}	
			for (int j=0;j<model1.getRowCount();j++)
			{
				for (int k=0;k<model2.getRowCount();k++) 
					if (model1.getValueAt(j, model1.findColumn(columnName1)).equals(model2.getValueAt(k, model2.findColumn(columnName2))))
					{
						List<String> values = new ArrayList<String>();
						for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(j, p).toString());
						for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(k, p).toString());
						resultModel.addRow(values.toArray()); 
					}
			}
			for (int i=0;i<insertedRow1.size();i++) 
			{
				List<String> values = new ArrayList<String>();
				for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(insertedRow1.get(i), p).toString());
				for (int p=0;p<model2.getColumnCount();p++) values.add(null);
				resultModel.addRow(values.toArray()); 
			}
			for (int i=0;i<insertedRow2.size();i++) 
			{
				List<String> values = new ArrayList<String>();
				for (int p=0;p<model1.getColumnCount();p++) values.add(null);
				for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(insertedRow2.get(i), p).toString());
				resultModel.addRow(values.toArray()); 
			}
		}
		else if (joinMode.equals("Right"))
		{
			List<Integer> insertedRow = new ArrayList<Integer>();
			for (int j=0;j<model2.getRowCount();j++)
			{
				boolean t = true;
				for (int k=0;k<model1.getRowCount();k++) 
					if (model1.getValueAt(k, model1.findColumn(columnName1)).equals(model2.getValueAt(j, model2.findColumn(columnName2))))
					{
						List<String> values = new ArrayList<String>();
						for (int p=0;p<model1.getColumnCount();p++) values.add(model1.getValueAt(k, p).toString());
						for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(j, p).toString());
						resultModel.addRow(values.toArray()); 
						t=false;
					}
				if (t) insertedRow.add(j);
			}	
			for (int i=0;i<insertedRow.size();i++) 
			{
				List<String> values = new ArrayList<String>();
				for (int p=0;p<model1.getColumnCount();p++) values.add(null);
				for (int p=0;p<model2.getColumnCount();p++) values.add(model2.getValueAt(insertedRow.get(i), p).toString());
				resultModel.addRow(values.toArray()); 
			}
		}
	}
	@Override
	public void visit(GreaterThan arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(GreaterThanEquals arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(InExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(IsNullExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(LikeExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(MinorThan arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(MinorThanEquals arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(NotEqualsTo arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Column column) 
	{
		columnName = column.getWholeColumnName();
	}
	@Override
	public void visit(SubSelect arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(CaseExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(WhenClause arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(ExistsExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(AllComparisonExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(AnyComparisonExpression arg0) {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void visit(Concat arg0) {
		// TODO Auto-generated method stub
		
	}
}
